/*************************************************************************
 * Copyright 2008 David Almilli
 *  
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0 
 *      
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 **************************************************************************/
package com.tivo.hme.bananas;

import static com.tivo.hme.bananas.IBananasPlus.*;

import com.tivo.hme.bananas.layout.Layout;
import com.tivo.hme.sdk.Resource;
import java.awt.Rectangle;
import java.text.Format;

public class BButtonPlus<E> extends BButton implements PlusView {
	private boolean highlightInit;
    private boolean disposeResourceOnRemove;
	
	protected E value;
    protected Object font;
    protected Object color;
    protected Format format;

    /**
     * Resource flags.
     */
    private int flags;

	public BButtonPlus(BView parent, int x, int y, int width, int height) {
		this(parent, x, y, width, height, true);
	}

	public BButtonPlus(BView parent, int x, int y, int width, int height, boolean visible) {
		this(parent, ViewUtils.getBounds(parent, x, y, width, height), visible);
	}

	public BButtonPlus(BView parent, int x, int y, int width) {
		this(parent, x, y, width, true);
	}

	public BButtonPlus(BView parent, int x, int y, int width, boolean visible) {
		this(parent, ViewUtils.getBounds(parent, x, y, width, H_BAR), visible);
	}

    public BButtonPlus(BView parent, Layout layout) {
        this(parent, layout, true);
    }

    public BButtonPlus(BView parent, Layout layout, boolean visible) {
        this(parent, layout.getManager().defaultHeight(layout, H_BAR).getBounds(), visible);
    }

	protected BButtonPlus(BView parent, Rectangle bounds, boolean visible) {
		super(parent, bounds.x, bounds.y, bounds.width, bounds.height, visible);
	}

    @Override
    public void remove(Resource animation) {
        PlusSupport.viewRemoveNotify(this);
        super.remove(animation);
    }
    
    protected void viewRemoveNotify() {
        if (getDisposeResourceOnRemove()) {
            Resource resource = getResource();
            if (resource != null) {
                //remove the resource
                resource.remove();
            }
        }
    }

    public boolean getDisposeResourceOnRemove() {
        return disposeResourceOnRemove;
    }

    public void setDisposeResourceOnRemove(boolean disposeResourceOnRemove) {
        this.disposeResourceOnRemove = disposeResourceOnRemove;
    }
    
    public Rectangle getScreenFocusBounds() {
        BPoint s = toScreen();
        return new Rectangle(s.x, s.y, getWidth(), getHeight());
    }
	
    /**
     * Get the highlights.
     *
     * <p>This is a thread-safe public entry point.</p>
     */
    @Override
    public BHighlightsPlus getHighlights() {
    	synchronized (lock) {
	    	if (!highlightInit) {
	    		highlightInit = true;
	    		super.setHighlights(new BHighlightsPlus(this));
	    	}
	    	return (BHighlightsPlus)super.getHighlights();
    	}
    }
    
    /**
     * Overridden to enforce the use of BHighlightsPlus.
     * @throws IllegalArgumentException if the highlights aren't an instance of BHighlightsPlus
     */
    @Override
    public void setHighlights(BHighlights highlights) throws IllegalArgumentException {
    	if (!(highlights instanceof BHighlightsPlus)) {
    		throw new IllegalArgumentException("You must use BHighlightsPlus with this view.");
    	}
    	super.setHighlights(highlights);
    }

	public E getValue() {
		return value;
	}

	public void setValue(E value) {
		this.value = value;
		refresh();
	}
	
	protected void refresh() {
	    synchronized (lock) {
            String text = null;
            if (value != null) {
                if (format != null) {
                    text = format.format(value);
                } else {
                    text = value.toString();
                }
            }

	        if (text != null) {
	            setResource(createText(getFont(), getColor(), text), flags);
	        }
	    }
	}

	public Object getFont() {
        if (font == null) {
            this.font = ViewUtils.getResource(this, H_BAR_FONT);
        }
		return font;
	}

	public void setFont(Object font) {
		synchronized (lock) {
			this.font = font;
			refresh();
		}
	}

	public Object getColor() {
        if (color == null) {
            this.color = ViewUtils.getResource(this, H_BAR_TEXT_COLOR);
        }
		return color;
	}

	public void setColor(Object color) {
		synchronized (lock) {
			this.color = color;
			refresh();
		}
	}

	public int getFlags() {
		return flags;
	}

	public void setFlags(int flags) {
		synchronized (lock) {
			this.flags = flags;
			refresh();
		}
	}

    public Format getFormat() {
        return format;
    }

    public void setFormat(Format format) {
        synchronized (lock) {
            this.format = format;
            refresh();
        }
    }

    /**
     * Fill the button with a bar and arrows.
     *
     * This is a thread-safe public entry point.
     *
     * @param bar_left If BAR_HANG, the bar extends off the side of the
     * screen. If BAR_DEFAULT, the bar touches the edge of the button. Otherwise
     * this is an offset from 0.
     * @param bar_right If BAR_HANG, the bar extends off the side of the
     * screen. If BAR_DEFAULT, the bar touches the edge of the button. If
     * negative, this is an offset from the right edge. If positive this is an
     * offset from the left edge.
     * @param action_left if not null, the button will contain a whispering left
     * arrow that fires this action.
     * @param action_right if not null, the button will contain a whispering
     * right arrow that fires this action.
     * @param action_up if not null, the button will contain a whispering up
     * arrow that fires this action.
     * @param action_down if not null, the button will contain a whispering down
     * arrow that fires this action.
     * @param inside if true, the arrows will be placed inside the
     * button. Otherwise they will be placed outside.
     */
    public void setBarAndArrows(int bar_left, int bar_right,
                                Object action_left, Object action_right,
                                Object action_up, Object action_down,
                                boolean inside) {
        setBarAndArrows(bar_left, bar_right, FLAG_DEFAULT, action_left, 
        		action_right, action_up, action_down, inside);
    }


    /**
     * Fill the button with a bar and arrows.
     * 
     * This is a thread-safe public entry point.
     * 
     * @param bar_left
     *            If BAR_HANG, the bar extends off the side of the screen. If BAR_DEFAULT, the bar
     *            touches the edge of the button. Otherwise this is an offset from 0.
     * @param bar_right
     *            If BAR_HANG, the bar extends off the side of the screen. If BAR_DEFAULT, the bar
     *            touches the edge of the button. If negative, this is an offset from the right
     *            edge. If positive this is an offset from the left edge.
     * @param bar_flags
     * 			  Sets the flags for the bar.  This is a bit mask of one or more 
     *            IBananasPlus.FLAG_XXX values
     * @param action_left
     *            if not null, the button will contain a whispering left arrow that fires this
     *            action.
     * @param action_right
     *            if not null, the button will contain a whispering right arrow that fires this
     *            action.
     * @param action_up
     *            if not null, the button will contain a whispering up arrow that fires this action.
     * @param action_down
     *            if not null, the button will contain a whispering down arrow that fires this
     *            action.
     * @param inside
     *            if true, the arrows will be placed inside the button. Otherwise they will be
     *            placed outside.
     */
    public void setBarAndArrows(int bar_left, int bar_right, int bar_flags,
                                Object action_left, Object action_right,
                                Object action_up, Object action_down,
                                boolean inside)
    {
        synchronized (lock) {
            BHighlights h = getHighlights();
        
            // create bar, left, right highlights
            if (h instanceof BHighlightsPlus) {
            	BHighlightsPlus hp = (BHighlightsPlus)h;
            	hp.setBarAndArrows(bar_left, bar_right, bar_flags, 0,
                        action_left, action_right,
                        inside);
            	hp.setVisible(H_BAR, hp.getVisibilityForFlags(bar_flags, H_VIS_TRUE));
            } else {
            	h.setBarAndArrows(bar_left, bar_right,
                              action_left, action_right,
                              inside);
            	h.setVisible(H_BAR, H_VIS_TRUE);
            }
    
            //
            // up/down arrows
            //
    
            BSkin skin = getBApp().getSkin();
            int whi_h = skin.get(H_UP).getHeight();
            int bar_padv = skin.get(H_BAR).getInt("padv", 4);
                
            if (action_up != null) {
                h.setWhisperingArrow(H_UP, A_CENTER,
                                     A_TOP - whi_h - bar_padv, action_up);
            } else {
                h.remove(H_UP);
            }
            
            if (action_down != null) {
                h.setWhisperingArrow(H_DOWN, A_CENTER,
                                     A_TOP + getHeight() + bar_padv, action_down);
            } else {
                h.remove(H_DOWN);
            }
        } // synch
    } // setBarAndArrows()

    /**
     * Overridden to support anchoring inside the parent view.
     */
	@Override
	public void setBounds(int x, int y, int width, int height, Resource animation) {
		Rectangle bounds = ViewUtils.getBounds(getParent(), x, y, width, height);
		super.setBounds(bounds.x, bounds.y, bounds.width, bounds.height, animation);
	}
    
    public void setBounds(Layout layout, Resource animation) {
        Rectangle bounds = layout.getBounds();
        super.setBounds(bounds.x, bounds.y, bounds.width, bounds.height, animation);
    }
    
}
